/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * filter.c
 * Copyright (C) chemek anouar 2012 <anouar.chemek@esprit.tn>
 *
 * WiScramb is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * WiScramb is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "filter.h"



/**
 * ieee80211_frame_process - process incomming frames
 * @buffer: The received buffer at lower layer (receivfrom call result)
 * Returns: NULL on success
 */
void * ieee80211_frame_process(void *buffer)
{
  struct ieee80211_mac_header *mac_h=NULL;
  struct ieee80211_radiotap_header *radio_h=NULL;

  char* radiohead=NULL; /*Pointer to radiotap Header*/
  char* machead=NULL; /*Pointer to mac Header*/

  int len_radiotap_header;


  while(1){
      buffer = ( char * ) malloc ( BUF_SIZE * sizeof ( char ));
      ieee80211_frame_sniff (buffer,sock_fd);
      radiohead = buffer;
      radio_h = ( struct ieee80211_radiotap_header * ) radiohead;
      len_radiotap_header = radio_h->header_lenght;
      machead = buffer + len_radiotap_header;
      mac_h = ( struct ieee80211_mac_header * ) machead;
      ieee80211_frame_filter(buffer,mac_h,radio_h);
      //print_mac_header_packet(mac_h);
      free(buffer);
  }
  return (NULL);
}

/*
void ieee80211_frame_delimiter(char *buffer,struct ieee80211_mac_header *mac_h,struct ieee80211_radiotap_header *radio_h)
{

  int len_radiotap_header;
  radiohead = buffer;
  radio_h = ( struct ieee80211_radiotap_header * ) radiohead;
  len_radiotap_header = radio_h->header_lenght;
  machead = buffer + len_radiotap_header;
  mac_h = ( struct ieee80211_mac_header * ) machead;
}*/

/**
 * ieee80211_frame_filter - filter each incomming frame
 * @buffer: The received buffer at lower layer (receivfrom call result)
 * @mac_h: the mac header frame
 * @radio_h: the radiotap hedar frame
 * Returns: void
 */
void ieee80211_frame_filter ( char *buffer,struct ieee80211_mac_header *mac_h,struct ieee80211_radiotap_header *radio_h )
{

  switch(mac_h->fc.type){

  case IEEE80211_FTYPE_MGMT:
    process_ieee80211_management(buffer,mac_h,radio_h);
    break;
  case IEEE80211_FTYPE_CTL:process_ieee80211_control(buffer,mac_h,radio_h);
  break;
  case IEEE80211_FTYPE_DATA:process_ieee80211_data(buffer,mac_h);
  break;
  default:break;

  }

}

/**
 * process_ieee80211_management - process each incomming management frame
 * @buffer: The received buffer at lower layer (receivfrom call result)
 * @mac_h: the mac header frame
 * Returns: void
 */
void process_ieee80211_management(char *buffer,struct ieee80211_mac_header *mac_h,struct ieee80211_radiotap_header *radio_h)
{


  struct ieee80211_mgmt *mgmt=NULL;

  char* management=NULL; /*Pointer to mgmt packet content*/

  management = buffer + radio_h->header_lenght + sizeof(struct ieee80211_mac_header);
  mgmt = ( struct ieee80211_mgmt * ) management;



  switch(mac_h->fc.sub_type){

  case IEEE80211_STYPE_ASSOC_REQ://printf("\n Association Request Frame\n");
    break;
  case IEEE80211_STYPE_ASSOC_RESP:printf("\n Association Responce Frame\n");
  break;
  case IEEE80211_STYPE_REASSOC_REQ:printf("\n Reassociation Request Frame\n");
  break;
  case IEEE80211_STYPE_REASSOC_RESP:printf("\n Reassociation Responce Frame\n");
  break;
  case IEEE80211_STYPE_PROBE_REQ:printf("\n Probe Request Frame\n");
  break;
  case IEEE80211_STYPE_PROBE_RESP:printf("\n Probe Responce Frame\n");
  break;
  case IEEE80211_STYPE_BEACON:printf("\n Beacon Frame \n");
  process_ieee80211_beacon(buffer,mac_h,radio_h,mgmt);
  break;
  case IEEE80211_STYPE_ATIM:printf("\n ATIM Frame\n");
  break;
  case IEEE80211_STYPE_DISASSOC:printf("\n Disassociation Frame\n");
  break;
  case IEEE80211_STYPE_AUTH:printf("\n Authentication Frame\n");
  break;
  case IEEE80211_STYPE_DEAUTH:printf("\n Deauthentication Frame\n");
  break;
  case IEEE80211_STYPE_ACTION:printf("\n Action Frame\n");
  break;
  default:;
  break;
  }

}

/**
 * process_ieee80211_beacon - process each incomming (beacon) frame
 * @buffer: The received buffer at lower layer (receivfrom call result)
 * @mac_h: the mac header frame
 * @bssidvector: list of Acces Points
 * Returns: void
 */
void process_ieee80211_beacon(char *buffer,struct ieee80211_mac_header *mac_h,struct ieee80211_radiotap_header *radio_h,struct ieee80211_mgmt *mgmt)
{
  int i;
  printf("\nbeacon frame");
  add_ap_to_apvector(mac_h,radio_h,mgmt);


  for(i=0;i<ap_number;i++){
      printf("\nAP %d: ",i);
      print_station_adress(apvector[i].bssid);
      printf("\nFREQ=%d",apvector[i].freq);
      printf("\nSSI=%d",apvector[i].ssi);
      printf("\nSSID=");
      puts(apvector[i].ssid);

  }
  printf("\n ap_number =%d",ap_number);

}

/**
 * process_ieee80211_data - process each data type frame
 * @buffer: The received buffer at lower layer (receivfrom call result)
 * @mac_h: the mac header frame
 * @stationvector: list of all station that emit data packets
 * Returns: void
 */
void process_ieee80211_data(char *buffer,struct ieee80211_mac_header *mac_h)
{
  int i;
  printf("\ndata frame");
  add_sta_to_stationvector(mac_h);

  for(i=0;i<sta_number;i++){
      printf("\nStation Number:%d",sta_number);
      printf("\nstation :%d",i);
      printf(" adress: ");
      print_station_adress(stationvector[i].adress);
      printf(" attached to AP: ");
      print_station_adress(stationvector[i].AP_adress);
  }
  printf("\n sta_number =%d",sta_number);

}

/**
 * process_ieee80211_control - process each incomming control typeframe
 * @buffer: The received buffer at lower layer (receivfrom call result)
 * @mac_h: the mac header frame
 * Returns: void
 */
void process_ieee80211_control(char *buffer,struct ieee80211_mac_header *mac_h,struct ieee80211_radiotap_header *radio_h)
{
  printf("\n control frame\n");


}

/**
 * add_ap_to_apvector - add each detected new access point to the AP_ Vector
 * @radio_h: The radio mac header (signal ssi, freq)
 * @mac_h: the mac header frame (bssid)
 * @mgmt: the frame managment beacon content (ssid, supported rates ...)
 * Returns: void
 */
void add_ap_to_apvector(struct ieee80211_mac_header *mac_h,struct ieee80211_radiotap_header *radio_h,struct ieee80211_mgmt *mgmt)
{
  int i;
  int exist=0;
  size_t baselen;
  struct ieee802_11_elems elems;

  for(i=0;(i< ap_number) && (!exist);i++){
      if(!strncmp((char*)mac_h->addr3,(char*)apvector[i].bssid,IEEE80211_ADDR_LEN))
        exist=1;
  }

  if(!exist){ //if the new bssid does not exist in the vector, add it

      memcpy(apvector[ap_number].bssid,mac_h->addr3,IEEE80211_ADDR_LEN);
      apvector[ap_number].freq=radio_h->channel_frequency;
      apvector[ap_number].ssi=radio_h->ssi_signal;
      //ssid_lenght=(int)mgmt->u.beacon.ssid_tag_length;
      baselen = (u_int8_t *) mgmt->u.beacon.variable - (u_int8_t *) mgmt;
      ieee802_11_parse_elems(mgmt->u.beacon.variable, buffer_len - baselen, &elems);
      memcpy(apvector[ap_number].ssid,elems.ssid,elems.ssid_len);
      ap_number +=1;

  }
}

/**
 * add_ap_to_apvector - add each detected new access point to the AP_ Vector
 * @radio_h: The radio mac header (signal ssi, freq)
 * @mac_h: the mac header frame (bssid)
 * @mgmt: the frame managment beacon content (ssid, supported rates ...)
 * Returns: void
 */
int add_sta_to_stationvector(struct ieee80211_mac_header *mac_h)
{
  int i;
  int exist=0;

  if(mac_h->fc.from_ds == 1){
      return (-1); //drop the frame (frame coming from the acces point)
  }

  for(i=0;(i< sta_number) && (!exist);i++){
      if(!strncmp((char*)mac_h->addr2,(char*)stationvector[i].adress,IEEE80211_ADDR_LEN)){
          //update station with new access point
          memcpy(stationvector[i].AP_adress,mac_h->addr3,IEEE80211_ADDR_LEN);
          exist=1;
      }
  }
  //add station to the station vector
  if(!exist){
      memcpy(stationvector[sta_number].adress,mac_h->addr2,IEEE80211_ADDR_LEN);
      memcpy(stationvector[sta_number].AP_adress,mac_h->addr3,IEEE80211_ADDR_LEN);
      sta_number++;
  }

  return (0);


}

